package nl.scalasim.ui

import java.awt.Font
import scala.swing._
import scala.swing.event.EditDone
import nl.scalasim.cli._
import java.util.{TimerTask, Timer}
import nl.scalasim.{GetState, Controller}
import scala.actors.{Future, Scheduler, Actor}

/**
 * Entry point for GUI
 *
 * @author Yigal Duppen
 * @since Nov 5, 2010
 */
object Main extends Application {

  val parser = new CLIParser()
  val setting = new Example1Setting()
  val level = new Level(setting)

  val map = new MapView(level)
  val actions = new Actions(level, map)

  val input = new TextField {

  }

  val main = new MainFrame {

    title = "ScalaSim"
    contents = new BorderPanel {

      layout(map) = BorderPanel.Position.Center
      layout(input) = BorderPanel.Position.South
    }

    menuBar = new MenuBar {
      val fileMenu = new Menu("File") {
        contents += new MenuItem(actions.saveAction)
        contents += new MenuItem(actions.loadAction)
      }
      contents += fileMenu

      val speedMenu = new Menu("Speed") {
        contents += new MenuItem(actions.pauseAction)
        contents += new MenuItem(actions.runAction)
        contents += new Separator()
        contents += new MenuItem(actions.slowAction)
        contents += new MenuItem(actions.normalAction)
        contents += new MenuItem(actions.fastAction)
      }
      contents += speedMenu
    }

    input.requestFocus
  }

  val guiController = new Reactor {

    listenTo(input)

    reactions += {
      case EditDone(source) if source == input && input.text.trim != "" => {
        val command = input.text
        input.text = ""

        parser.parse(command) match {
          case Go(n) => {
            actions.stepAction()
          }
          case Describe(location) => {
            level.choreographer.send(location, GetState) foreach { f: Future[Any] =>
              Dialog.showMessage(map, f(), "Info", Dialog.Message.Info)
            }
          }
          case Build(descriptor, location) => {
            setting.types find {d => d.name == descriptor} match {
              case None => println("Unknown structure: " + descriptor)
              case Some(d) => {
                if (!level.controller.canAdd(d, location)) {
                  Dialog.showMessage(map, "You cannot build " + descriptor + " at this location", "Error", Dialog.Message.Error)
                }
                else {
                  level.controller.add(d, location) match {
                    case None => println("Could not add " + descriptor + " at " + location)
                    case Some(actor) => println("Added " + descriptor)
                  }
                  map.updateMap()
                }
              }
            }
          }
          case unknown@_ => {
            println("Cannot handle " + unknown)
          }
        }
      }
    }
  }

  println(Scheduler.impl)
  main.open

  map.updateMap()
}